﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Plan;

namespace PlanVisualization
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        #region props

        public string InstanceDescription
        {
            get { return (string)GetValue(InstanceDescriptionProperty); }
            set { SetValue(InstanceDescriptionProperty, value); }
        }

        public static readonly DependencyProperty InstanceDescriptionProperty =
            DependencyProperty.Register("InstanceDescription", typeof(string), typeof(MainWindow), new UIPropertyMetadata(""));


        public Associations Associationes
        {
            get { return (Associations)GetValue(AssociationesProperty); }
            set { SetValue(AssociationesProperty, value); }
        }

        public static readonly DependencyProperty AssociationesProperty =
            DependencyProperty.Register("Associationes", typeof(Associations), typeof(MainWindow), new UIPropertyMetadata(new Associations()));



        public int SubjectsPerGroup
        {
            get { return (int)GetValue(SubjectsPerGroupProperty); }
            set { SetValue(SubjectsPerGroupProperty, value); }
        }

        public static readonly DependencyProperty SubjectsPerGroupProperty =
            DependencyProperty.Register("SubjectsPerGroup", typeof(int), typeof(MainWindow), new UIPropertyMetadata(10));


        public ScheduleSolution Solution
        {
            get { return (ScheduleSolution)GetValue(SolutionProperty); }
            set { SetValue(SolutionProperty, value); }
        }

        public static readonly DependencyProperty SolutionProperty =
            DependencyProperty.Register("Solution", typeof(ScheduleSolution), typeof(MainWindow), new UIPropertyMetadata(null));



        public int TeacherCount
        {
            get { return (int)GetValue(TeacherCountProperty); }
            set { SetValue(TeacherCountProperty, value); }
        }

        public static readonly DependencyProperty TeacherCountProperty =
            DependencyProperty.Register("TeacherCount", typeof(int), typeof(MainWindow), new UIPropertyMetadata(3));

        

        public static DependencyProperty GroupCountProperty = DependencyProperty.Register("GroupCount", typeof(int), typeof(MainWindow),
                                                                         new PropertyMetadata(3));

        public int GroupCount
        {
            get { return (int)GetValue(GroupCountProperty); }
            set { SetValue(GroupCountProperty, value); }
        }

        public static DependencyProperty RoomCountProperty = DependencyProperty.Register("RoomCount", typeof(int), typeof(MainWindow),
                                                                                 new PropertyMetadata(2));

        public int RoomCount
        {
            get { return (int)GetValue(RoomCountProperty); }
            set { SetValue(RoomCountProperty, value); }
        }

        public static DependencyProperty SubjectCountProperty = DependencyProperty.Register("SubjectCount", typeof(int), typeof(MainWindow),
                                                                                 new PropertyMetadata(10));
        public int SubjectCount
        {
            get { return (int)GetValue(SubjectCountProperty); }
            set { SetValue(SubjectCountProperty, value); }
        }


        public int SpecialSubjectCount
        {
            get { return (int)GetValue(SpecialSubjectCountProperty); }
            set { SetValue(SpecialSubjectCountProperty, value); }
        }

        public static readonly DependencyProperty SpecialSubjectCountProperty =
            DependencyProperty.Register("SpecialSubjectCount", typeof(int), typeof(MainWindow), new UIPropertyMetadata(0));


        public static DependencyProperty SolutionQualityProperty = DependencyProperty.Register("SolutionQuality", typeof(int), typeof(MainWindow),
                                                                                 new PropertyMetadata(0));

        public int SolutionQuality
        {
            get { return (int)GetValue(SolutionQualityProperty); }
            set { SetValue(SolutionQualityProperty, value); }
        }

        public static DependencyProperty IterationCountProperty = DependencyProperty.Register("IterationCount", typeof(int), typeof(MainWindow),
                                                                                 new PropertyMetadata(10000));

        public int IterationCount
        {
            get { return (int)GetValue(IterationCountProperty); }
            set { SetValue(IterationCountProperty, value); }
        }

        public static DependencyProperty DayCountProperty = DependencyProperty.Register("DayCount", typeof(int), typeof(MainWindow),
                                                                                 new PropertyMetadata(2));

        public int DayCount
        {
            get { return (int)GetValue(DayCountProperty); }
            set { SetValue(DayCountProperty, value); }
        }

        public static DependencyProperty LessonsPerDayProperty = DependencyProperty.Register("LessonsPerDay", typeof(int), typeof(MainWindow),
                                                                                 new PropertyMetadata(8));

        public int LessonsPerDay
        {
            get { return (int)GetValue(LessonsPerDayProperty); }
            set { SetValue(LessonsPerDayProperty, value); }
        }

        public static DependencyProperty DedicatedClassroomCountProperty = DependencyProperty.Register("DedicatedClassroomCount", typeof(int), typeof(MainWindow),
                                                                                 new PropertyMetadata(0));

        public int DedicatedClassroomCount
        {
            get { return (int)GetValue(DedicatedClassroomCountProperty); }
            set { SetValue(DedicatedClassroomCountProperty, value); }
        }

        public static DependencyProperty InProgressProperty = DependencyProperty.Register("InProgress", typeof(bool), typeof(MainWindow),
                                                                                 new PropertyMetadata(false));

        public bool InProgress
        {
            get { return (bool)GetValue(InProgressProperty); }
            set { SetValue(InProgressProperty, value); }
        }

        public static DependencyProperty ProgressProperty = DependencyProperty.Register("Progress", typeof(double), typeof(MainWindow),
                                                                                 new PropertyMetadata(0.0));

        public double Progress
        {
            get { return (double)GetValue(ProgressProperty); }
            set { SetValue(ProgressProperty, value); }
        }

        public static DependencyProperty VisualizationProperty = DependencyProperty.Register("Visualization", typeof(bool), typeof(MainWindow),
                                                                                 new PropertyMetadata(true));

        public bool Visualization
        {
            get { return (bool)GetValue(VisualizationProperty); }
            set { SetValue(VisualizationProperty, value); }
        }


        public string Shits
        {
            get { return (string)GetValue(ShitsProperty); }
            set { SetValue(ShitsProperty, value); }
        }

        public static readonly DependencyProperty ShitsProperty =
            DependencyProperty.Register("Shits", typeof(string), typeof(MainWindow), new UIPropertyMetadata(""));


        #endregion

        private SimulatedAnnealingAlgoritm _alg;
        private ScheduleInstance.GenerateParams _generateParams;
        private ScheduleInstance _problemInstance;
        private bool _cancel = false;
        private bool _visualize;
        private ScheduleSolution _bestSolution;

        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;

        }
        void Calculate()
        {
            ScheduleSolution solution;
            try
            {
                solution = _alg.Solve(_problemInstance);
            }
            catch (ProblemUnsolvable ex)
            {
                MessageBox.Show(ex.Message);
                return;
            }


            Console.WriteLine(solution.ToString());
            Console.WriteLine("Shittness: {0:0}", solution.PlanShitness());
            Console.ReadLine();
        }

        void alg_ReportProgress(object sender, ReportProgressArgs e)
        {
            Dispatcher.BeginInvoke(new Action(delegate
                                         {
                                             _bestSolution = e.BestSolution;
                                             if (Visualization)
                                                 scheduleControl.Solution = _bestSolution;

                                             SolutionQuality = e.BestSolution.PlanShitness();
                                             Progress = e.Progress ?? 0;
                                             Shits = e.LogMessage.Shits;
                                         }));
            if (_cancel)
                e.Cancel = true;
            Console.WriteLine("{0}", e.LogMessage.Message);
        }

        private void goButton_Click(object sender, RoutedEventArgs e)
        {
            CalculateWrapper();
        }

        private void CalculateWrapper()
        {
            InProgress = true;
            Progress = 0;
            _cancel = false;
            _bestSolution = null;
            _generateParams = new ScheduleInstance.GenerateParams
                                  {
                                      GroupCount = GroupCount,
                                      RoomCount = RoomCount,
                                      SubjectCount = SubjectCount,
                                      TeacherCount = TeacherCount
                                  };

            try { _alg.ReportProgress -= alg_ReportProgress; }
            catch { }
            _alg = new SimulatedAnnealingAlgoritm
            {
                IterationCount = IterationCount
            };
            _alg.ReportProgress += alg_ReportProgress;

            var generator = new Random();
            _problemInstance = ScheduleInstance.GenerateRandom(generator, _generateParams);
            _problemInstance.DayCount = DayCount;
            _problemInstance.LessonsPerDay = LessonsPerDay;
            for (int i = 0; i < DedicatedClassroomCount && i < _problemInstance.ClassroomsCount && i < _problemInstance.Subjects.Count; i++)
            {
                _problemInstance.Classrooms[i].DedicatedSubject = _problemInstance.Subjects[i].Id;
                if (i < SpecialSubjectCount)
                    _problemInstance.Subjects[i].NeedsDedicatedClassroom = true;
            }
            if (SubjectCount >= TeacherCount)
                for (int i = 0; i < SubjectCount; i++)
                    _problemInstance.Teachers[i % TeacherCount].Subjects.Add(i);
            else
                for (int i = 0; i < TeacherCount; i++)
                    _problemInstance.Teachers[i].Subjects.Add(i % SubjectCount);

            for (int i = 0; i < GroupCount; i++)
            {
                int off = generator.Next(SubjectCount);
                for (int j = 0; j < SubjectsPerGroup; j++)
                {
                    _problemInstance.Groups[i].Subjects.Add((j + off) % SubjectCount);
                }
            }
            InstanceDescription = _problemInstance.ToString();
            
            Action a = Calculate;
            a.BeginInvoke(GeneratingFinished, null);
        }

        private void GeneratingFinished(IAsyncResult ar)
        {
            Dispatcher.BeginInvoke(new Action(delegate
            {
                _cancel = false;
                Progress = 1;
                InProgress = false;
                Visualization = true;
                scheduleControl.Solution = _bestSolution;
                if (_bestSolution != null) Shits = _bestSolution.Shits;
            }));
        }

        private void realWorldData_Click(object sender, RoutedEventArgs e)
        {
            TeacherCount = 6;
            GroupCount = 8;
            SubjectCount = 15;
            DedicatedClassroomCount = 4;
            DayCount = 5;
            LessonsPerDay = 9;
            RoomCount = 15;
        }

        private void stopButton_Click(object sender, RoutedEventArgs e)
        {
            _cancel = true;
        }

        private void EditAssociationsButton_Click(object sender, RoutedEventArgs e)
        {
            Associationes.GenerateLists(SubjectCount, GroupCount, TeacherCount);

            var assWindow = new AssociationsWindows { Associations = Associationes };
            assWindow.ShowDialog();
        }
        public class Associations
        {
            List<int> _subjects = new List<int>();
            List<int> _groups = new List<int>();

            public List<int> Groups
            {
                get { return _groups; }
                set { _groups = value; }
            }
            List<int> _teachers = new List<int>();

            public List<int> Teachers
            {
                get { return _teachers; }
                set { _teachers = value; }
            }

            public Associations() : this(0,0,0)
            {

            }
            public List<int> Subjects
            {
                get { return _subjects; }
                set { _subjects = value; }
            }
            List<List<int>> _groupToSubject = new List<List<int>>();

            public List<List<int>> GroupToSubject
            {
                get { return _groupToSubject; }
                set { _groupToSubject = value; }
            }
            List<List<int>> _teacherToSubject = new List<List<int>>();

            public List<List<int>> TeacherToSubject
            {
                get { return _teacherToSubject; }
                set { _teacherToSubject = value; }
            }
            public void GenerateLists(int subjectCount, int groupCount, int teacherCount){
                for (int i = _subjects.Count; i < subjectCount; i++)                
                    _subjects.Add(i);
                for (int i = _teachers.Count; i < teacherCount; i++)
                {
                    _teachers.Add(i);
                    _teacherToSubject.Add(new List<int>());
                }
                for (int i = _groups.Count; i < groupCount; i++)
                {
                    _groupToSubject.Add(new List<int>());
                    _groups.Add(i);
                }
            }

            public Associations(int subjectCount, int groupCount, int teacherCount)
            {
                GenerateLists(subjectCount, groupCount, teacherCount);

                _groupToSubject = new List<List<int>>(groupCount);
                _teacherToSubject = new List<List<int>>(teacherCount);
            }
        }
    }
}
